package com.ke.rule.base;

import com.google.common.collect.Maps;

import java.util.LinkedHashMap;
import java.util.Map;

public class Problem implements Cloneable {
  /* 字段所在的路径, 可以为null表示不是字段错误 */
  private String fieldPath;
  /* 错误类型：ERROR/WARNING */
  protected ProblemTypeEnum type;
  /* 分组名, 可以任意写 */
  protected String group;
  /* 错误编码 */
  protected String code;
  /* 错误消息: 如果有code, 由code生成 */
  protected String message;
  /* 其他描述信息 */
  protected String description;
  /* 是否为相关对象引起的问题， 这类问题， 前端显示错误时，自动显示一次 */
  protected Boolean isRelated;
  /* 参数, 以KV方式提供，有序的map */
  protected LinkedHashMap<String, Object> args;
  /* 对象id，在做批量检查是，设置具体的对象id */
  protected String objectId;

  public Problem() {
    super();
  }
  
  public Problem(ProblemTypeEnum type, String group, String code,
                 LinkedHashMap<String, Object> args) {
    super();
    this.type = type;
    this.group = group;
    this.code = code;
    this.args = args;
    this.fieldPath = null;
  }

  public Problem(String fieldPath, ProblemTypeEnum type, String code,
                 Map<String, Object> args) {
    super();
    this.fieldPath = fieldPath;
    this.type = type;
    this.code = code;
    this.args = null == args ? null : Maps.newLinkedHashMap(args);
  }
  
  public Problem(String fieldPath, ProblemTypeEnum type, String group, String code,
                 LinkedHashMap<String, Object> args) {
    super();
    this.fieldPath = fieldPath;
    this.type = type;
    this.group = group;
    this.code = code;
    this.args = args;
  }
  
  public Problem(String fieldPath, ProblemTypeEnum type, String group, String code, String message, LinkedHashMap<String, Object> args) {
    super();
    this.fieldPath = fieldPath;
    this.type = type;
    this.group = group;
    this.code = code;
    this.message = message;
    this.args = args;
  }

  public ProblemTypeEnum getType() {
    return type;
  }

  public void setType(ProblemTypeEnum type) {
    this.type = type;
  }

  public String getGroup() {
    return group;
  }

  public void setGroup(String group) {
    this.group = group;
  }

  public String getCode() {
    return code;
  }

  public void setCode(String code) {
    this.code = code;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public LinkedHashMap<String, Object> getArgs() {
    return args;
  }

  public void setArgs(LinkedHashMap<String, Object> args) {
    this.args = args;
  }

  public String getObjectId() {
    return objectId;
  }

  public void setObjectId(String objectId) {
    this.objectId = objectId;
  }

  /**
   * 取字段相对于验证对象的相对路径，路径构成分两类：
   * <li>1. 对象的属性，路径为属性名，eg. name
   * <li>2. 数组的下标，以括号括起来的索引号，从0开始，eg. [0], [1]等 路径可以是多级，每级之间用点分隔，eg. items[0].name
   * 表示对象的items属性的第0个元素的name字段
   */
  public String getFieldPath() {
    return fieldPath;
  }

  /**
   * 设置字段相对于验证对象的相对路径，路径构成分两类：
   * <li>1. 对象的属性，路径为属性名，eg. name
   * <li>2. 数组的下标，以括号括起来的索引号，从0开始，eg. [0], [1]等 路径可以是多级，每级之间用点分隔，eg. items[0].name
   * 表示对象的items属性的第0个元素的name字段
   * 
   * @param fieldPath
   */
  public void setFieldPath(String fieldPath) {
    this.fieldPath = fieldPath;
  }
  
  /**
   * 是否为相关对象引起的问题， 如果为true, 前端显示时，默认只显示一次 
   * @return
   */
  public Boolean getIsRelated() {
    return isRelated;
  }

  /**
   * 设置是否为相关对象引起的问题， 如果为true, 前端显示时，默认只显示一次 
   * @param isRelated
   */
  public void setIsRelated(Boolean isRelated) {
    this.isRelated = isRelated;
  }

  @Override
  public Problem clone() {
    Problem p = new Problem(fieldPath, type, group, code, args);
    p.message = this.message;
    p.description = this.description;
    p.isRelated = this.isRelated;
    p.objectId = this.objectId;
    return p;
  }

  /**
   *  创建一个Problem对象
   * @param code 错误编码
   * @param args 错误编码中的参数，偶数个，依次为每一个Key,Value值
   * @return
   */
  public static Problem create(String code, Object... args) {
    Problem p = new Problem();
    p.setCode(code);
    if(args != null && args.length > 0){
      if(args.length % 2 != 0){
        throw new RuntimeException("args must be even number");
      }
      LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
      for(int i = 0; i < args.length; i += 2) {
        map.put(args[i].toString(), args[i + 1]);
      }
      p.setArgs(map);
    }
    return p;
  }
}
